package com.oa.common.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.junit.Test;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;
import java.io.FileInputStream;


/**
 * @Author: Hankaicheng
 * @Date: 2022/3/15 10:32
 */
@Log4j2
@Component
public class PdfUtil {

    //存储签名信息
    List<CoordInfo> coords = new ArrayList<CoordInfo>();
    //所有需签名的字段
    private String[] tags = new String[]{"被核查人签章：","培训机构负责人签字：", "负责人签字：", "申请人签字：", "申请人签名：", "法人（负责人）签字：", "负责人：", "申请人：", "法定代表人（签字）："};
    //需要签名的页数
    private ArrayList<Integer> pages;
    //正在遍历的页数
    private int currentPage = 0;
    //获取pdf总页数
    private int pageNum = 0;
    //每页的数据
    private StringBuilder texts = new StringBuilder();

    private static String randomPath(String suffix) {
//        String path = "/home/file/examination-approval-project/" + AppUtils.getUUID() + "/" + AppUtils.getUUID() + suffix;
        String path="E:/file/examination-approval-project/"+AppUtils.getUUID()+"/"+AppUtils.getUUID() + suffix;
        File file = new File(path);
        if (!FileUtil.exist(file)) {
            FileUtil.touch(file);
        }
        return path;
    }

    public static boolean docToPdf(String inPath, String outPath) {
        FontSettings fontSettings = new FontSettings();
        fontSettings.setFontsFolder("/usr/share/fonts/", false);
        if (!getLicense()) {
            return false;
        }
        FileOutputStream os = null;
        try {
            File file = new File(outPath);
            os = new FileOutputStream(file);
            Document doc = new Document(inPath);
            doc.save(os, SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (os != null) {
                try {
                    os.flush();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    public static boolean getLicense() {
        boolean result = false;
        try {
            InputStream inputStream = new FileInputStream(new File("/usr/share/fonts/license.xml"));
//            InputStream inputStream = new FileInputStream(new File("E:\\项目\\examination-approval\\src\\main\\resources\\license.xml"));
            License aposeLic = new License();
            aposeLic.setLicense(inputStream);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void xlsToPdf(String inPath, String outPath) {
        PDFConverter excelConverter = new PDF2ExcelConverter();
        excelConverter.convert(new File(inPath), new File(outPath));
    }

    /**
     * 图片转pdf
     *
     * @param path 图片地址
     * @return
     */
    public static String imgToPdf(String path) {
        com.itextpdf.text.Document document = new com.itextpdf.text.Document();
        document.setMargins(0, 0, 0, 0);
        String filePath = randomPath(".pdf");
        try {
            FileOutputStream fos = null;
            if (!FileUtil.exist(filePath)) {
                FileUtil.touch(filePath);
            }
            fos = new FileOutputStream(filePath);
            PdfWriter.getInstance(document, fos);
            document.open();
            document.setPageCount(1);
            Image image = Image.getInstance(path);
            float imageHeight = image.getScaledHeight();
            float imageWidth = image.getScaledWidth();
            Rectangle rectangle = new Rectangle(imageWidth, imageHeight);
            document.setPageSize(rectangle);
            image.setAlignment(Image.ALIGN_CENTER);
            document.newPage();
            document.add(image);
            document.close();
            if (fos != null) {
                try {
                    fos.flush();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return filePath.replaceAll("/home/image", "https://www.qhspj.com").replaceAll("/home/file", "https://www.qhspj.com");
    }

    @Test
    public void test() throws IOException {
        getCoordInfo("C:\\Users\\yuyan\\Downloads\\666.pdf", "D:\\签名.png");
    }

    /**
     * 获取坐标信息
     *
     * @param target 源文件地址
     * @param sign   签名图片url
     * @return
     */
    public String getCoordInfo(String target, String sign) throws IOException {
        PdfReader reader = new PdfReader(target);
        PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(reader);
        pageNum = reader.getNumberOfPages();
        pages = new ArrayList<>(pageNum);

        //pdf的每页进行遍历
        for (int i = 1; i <= pageNum; i++) {
            currentPage = i;
            //遍历每页时把上一页的数据清空
            texts.delete(0, texts.length());
            pdfReaderContentParser.processContent(i, new RenderListener() {
                @Override
                public void beginTextBlock() {

                }

                @Override
                public void renderText(TextRenderInfo renderInfo) {
                    //将读到的数据存入texts
                    texts.append(renderInfo.getText());
                    //循环遍历签名的标题
                    for (String tag : tags) {
                        //在当前读到的数据中含有签名的字段时
                        if (texts.lastIndexOf(tag) != -1) {
                            Rectangle2D.Float boundingRectange = renderInfo.getBaseline().getBoundingRectange();
                            //判断签名字段是否是新读到的
                            CoordInfo cinfo = isNewRead(coords, tag);
                            if (cinfo != null) {
                                break;
                            } else {
                                //找到新的需要签名的字段就把他放到集合里
                                CoordInfo coordInfo = new CoordInfo();
                                coordInfo.setPage(currentPage);
                                coordInfo.setX(boundingRectange.x + boundingRectange.width + 20);
                                coordInfo.setY(boundingRectange.y);
                                coordInfo.setTag(tag);
                                log.error(renderInfo.getText());
                                coords.add(coordInfo);
                                System.out.println(coords.size());
                            }

                        }
                    }
                }

                @Override
                public void endTextBlock() {

                }

                @Override
                public void renderImage(ImageRenderInfo renderInfo) {

                }
            });
        }
        log.error("开始签名");
        log.error("签名个数：" + coords.size());

        //获取签完字的文件地址
        String signPath = signature(target, sign, coords);
        //创建新的文件地址，文件名是源文件名加当前时间
        String newFile = target.substring(0, target.lastIndexOf(".")) + DateUtil.format(new Date(), "yyyy-MM-dd") + ".pdf";
        File file = new File(newFile);
        if (!FileUtil.exist(file)) {
            FileUtil.touch(file);
        }
        //将签完字的文件copy到新文件中
        FileUtil.copy(signPath, newFile, true);
        //删除签完字的文件，这样的意义是文件名不再是uuid
        FileUtil.del(signPath);
        return newFile;
    }

    public CoordInfo isNewRead(List<CoordInfo> coords, String tag) {
        CoordInfo cinfo = coords.stream().filter(i -> i.getTag().equals(tag)).filter(i -> i.getPage() == currentPage).findFirst().orElse(null);
        return cinfo;
    }

    /**
     * 签名
     *
     * @param target   源文件url
     * @param signPath 签名文件地址
     */
    public String signature(String target, String signPath, List<CoordInfo> coords) {
        //用来存储临时文件
        List<String> tempPath = new ArrayList<String>();
        //获取一个临时文件，将源文件复制到新的文件上
        String temp = randomPath(".pdf");
        FileUtil.copy(target, temp, true);
        for (int i = 0; i < coords.size(); i++) {
            log.error("签名信息:" + coords.get(i).toString());
            log.error("源文件地址：" + temp);
            try {
                PdfReader reader = new PdfReader(temp, "PDF".getBytes());
                String source = randomPath(".pdf");
                log.error("签名后的文件地址：" + source);
                PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(source));
                com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(signPath);
                img.setAbsolutePosition(coords.get(i).getX(), coords.get(i).getY() - (img.getHeight() / 2));
                PdfContentByte under = stamper.getUnderContent(coords.get(i).getPage());
                under.addImage(img);
                stamper.close();
                reader.close();
                tempPath.add(temp);
                temp = source;
                log.error("签名完成！！,第" + (i + 1) + "个");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //删除临时文件
        log.error("删除临时文件，临时文件个数：{}", tempPath.size());
        for (String s : tempPath) {
            com.oa.common.utils.FileUtil.deleteFile(s);
        }
        return temp;
    }


    /**
     * 获取坐标信息
     *
     * @param target 源文件地址
     * @return
     */
    public List<Map<String, Object>> getPosition(String target) throws IOException {
        PdfReader reader = new PdfReader(target);
        PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(reader);
        pageNum = reader.getNumberOfPages();
        pages = new ArrayList<>(pageNum);
        List<Map<String, Object>> list = new ArrayList<>();
        List<CoordInfo> clist = new ArrayList<>();

        //pdf的每页进行遍历
        for (int i = 1; i <= pageNum; i++) {
            currentPage = i;
            //遍历每页时把上一页的数据清空
            texts.delete(0, texts.length());
            pdfReaderContentParser.processContent(i, new RenderListener() {
                @Override
                public void beginTextBlock() {

                }

                @Override
                public void renderText(TextRenderInfo renderInfo) {
                    //将读到的数据存入texts
                    texts.append(renderInfo.getText());
                    //循环遍历签名的标题
                    for (String tag : tags) {
                        //在当前读到的数据中含有签名的字段时
                        if (texts.lastIndexOf(tag) != -1) {
                            Rectangle2D.Float boundingRectange = renderInfo.getBaseline().getBoundingRectange();
                            //判断签名字段是否是新读到的
                            CoordInfo cinfo = isNewRead(clist, tag);
                            if (cinfo != null) {
                                break;
                            } else {
                                //找到新的需要签名的字段就把他放到集合里
                                CoordInfo coordInfo = new CoordInfo();
                                coordInfo.setPage(currentPage);
                                coordInfo.setX(boundingRectange.x + boundingRectange.width + 20);
                                coordInfo.setY(boundingRectange.y);
                                coordInfo.setTag(tag);
                                log.error(renderInfo.getText());
                                clist.add(coordInfo);
                                System.out.println(clist.size());

                                Map<String, Object> map = new HashMap<>();
                                //页码
                                map.put("pageNumber", currentPage);
                                //横坐标
                                map.put("horizontal", Double.valueOf(boundingRectange.x + boundingRectange.width + 10));
                                //纵坐标
                                float height = reader.getPageSize(currentPage).getHeight();
                                map.put("vertical", Double.valueOf(height - boundingRectange.y - 25.0));
                                //签名宽
                                map.put("width", 50.0);
                                //签名高
                                map.put("hight", 50.0);
                                list.add(map);
                            }

                        }
                    }
                }

                @Override
                public void endTextBlock() {

                }

                @Override
                public void renderImage(ImageRenderInfo renderInfo) {

                }
            });
        }
        log.error("开始签名");
        log.error("签名个数：" + clist.size());

        return list;
    }

}


@Data
class CoordInfo {
    /**
     * 所在页
     */
    private Integer page;
    /**
     * X轴
     */
    private Float x;
    /**
     * Y轴
     */
    private Float y;

    /**
     * 签名标题
     */
    private String tag;

    @Override
    public String toString() {
        return "CoordInfo{" +
                "page=" + page +
                ", x=" + x +
                ", y=" + y +
                ", tag='" + tag + '\'' +
                '}';
    }
}
